package com.zlm.common.util;

import com.zlm.common.constants.CodeConstants;
import com.zlm.common.constants.FileConstants;
import com.zlm.common.enums.FileTypeEnum;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import java.io.*;
import java.util.*;

/**
 * 文件上传工具类
 * @author xhj
 */
public class FileUtils {

    /**
     * 文件上传
     * @param request
     * @param uploadType 上传文件类型 1 用户头像
     * @return
     */
    public static List<String> fileUpload(HttpServletRequest request, String uploadType) throws Exception {
        List<String> fileNames = new ArrayList<>();
        String savePath = FileConstants.getPath(uploadType);

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        Integer year = calendar.get(Calendar.YEAR);
        Integer month = calendar.get(Calendar.MONTH) + 1;
        Integer day = calendar.get(Calendar.DATE);

        savePath = savePath + year + FileConstants.SEPARATOR + month + FileConstants.SEPARATOR + day + FileConstants.SEPARATOR;

        File file = new File(FileConstants.ROOT_PATH + savePath);

        try {
            if (!file.exists() && !file.isDirectory() && !file.mkdirs()) {
                throw new RuntimeException("Permission denied");
            }

            Collection<Part> parts = request.getParts();
            if (parts.size() > 0) {
                for (Part part : parts) {
                    String header = part.getHeader("content-disposition");
                    if (header.indexOf("filename") != -1) {
                        String newName = UUID.randomUUID().toString();
                        String fileName = savePath + newName + getSuffix(header);
                        String fullName = FileConstants.ROOT_PATH + fileName;
                        part.write(fullName);

                        if (isTypeCorrect(fullName, uploadType)) {
                            fileNames.add(fileName);
                        } else {
                            deleteFile(fullName);
                            throw new Exception(CodeConstants.CODE_90001);
                        }
                    }
                }
            }
        } catch (IOException e) {
            throw new IOException(e.getMessage());
        } catch (ServletException e) {
            throw new ServletException(e.getMessage());
        }

        return fileNames;
    }

    /**
     * 判断文件格式是否正确
     * @param file
     * @param uploadType
     * @return
     * @throws Exception
     */
    public static Boolean isTypeCorrect(String file, String uploadType) throws Exception {
        InputStream inputStream = new FileInputStream(new File(file));
        Boolean isFileType = isFileType(getType(inputStream)).intValue() == FileConstants.getType(uploadType).intValue();
        inputStream.close();

        return isFileType;
    }

    /**
     * 删除文件
     * @param fileName
     */
    public static void deleteFile(String fileName) {
        File file = new File(fileName);
        if (file.exists() && file.isFile()) {
            file.delete();
        }
    }

    /**
     * 通过header获取文件的名字
     * @param header
     * @return
     */
    public static String getSuffix(String header) {
        String fileName = null;
        fileName = header.substring(header.indexOf("filename") + 2 + "filename".length(), header.length() - 1);
        String suffix = fileName.substring(fileName.lastIndexOf("."));
        return suffix;
    }

    /**
     * 将文件头转换成16进制字符串
     *
     * @param src
     * @return 16进制字符串
     */
    private static String bytesToHexString(byte[] src) {

        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 得到文件头
     *
     * @param is 文件流
     * @return 文件头
     * @throws IOException
     */
    private static String getFileContent(InputStream is) throws IOException {

        byte[] b = new byte[28];

        InputStream inputStream = null;

        try {
            is.read(b, 0, 28);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw e;
                }
            }
        }
        return bytesToHexString(b);
    }

    /**
     * 判断文件类型
     *
     * @param is 文件流
     * @return 文件类型
     */
    public static FileTypeEnum getType(InputStream is) throws IOException {

        String fileHead = getFileContent(is);
        if (fileHead == null || fileHead.length() == 0) {
            return null;
        }
        fileHead = fileHead.toUpperCase();
        FileTypeEnum[] fileTypes = FileTypeEnum.values();

        for (FileTypeEnum type : fileTypes) {
            if (fileHead.startsWith(type.getValue())) {
                return type;
            }
        }

        return null;
    }

    /**
     *
     * @param value 表示文件类型
     * @return 1 表示图片,2 表示文档,3 表示视频,4 表示种子,5 表示音乐,6 表示其它
     * @return
     */
    public static Integer isFileType(FileTypeEnum value) {
        // 其他
        Integer type = 6;
        // 图片
        FileTypeEnum[] pics = { FileTypeEnum.JPEG, FileTypeEnum.PNG, FileTypeEnum.GIF, FileTypeEnum.TIFF, FileTypeEnum.BMP, FileTypeEnum.DWG, FileTypeEnum.PSD };

        FileTypeEnum[] docs = { FileTypeEnum.RTF, FileTypeEnum.XML, FileTypeEnum.HTML, FileTypeEnum.CSS, FileTypeEnum.JS, FileTypeEnum.EML, FileTypeEnum.DBX, FileTypeEnum.PST, FileTypeEnum.XLS_DOC, FileTypeEnum.XLSX_DOCX, FileTypeEnum.VSD,
                FileTypeEnum.MDB, FileTypeEnum.WPS, FileTypeEnum.WPD, FileTypeEnum.EPS, FileTypeEnum.PDF, FileTypeEnum.QDF, FileTypeEnum.PWL, FileTypeEnum.ZIP, FileTypeEnum.RAR, FileTypeEnum.JSP, FileTypeEnum.JAVA, FileTypeEnum.CLASS,
                FileTypeEnum.JAR, FileTypeEnum.MF, FileTypeEnum.EXE, FileTypeEnum.CHM };

        FileTypeEnum[] videos = { FileTypeEnum.AVI, FileTypeEnum.RAM, FileTypeEnum.RM, FileTypeEnum.MPG, FileTypeEnum.MOV, FileTypeEnum.ASF, FileTypeEnum.MP4, FileTypeEnum.FLV, FileTypeEnum.MID };

        FileTypeEnum[] tottents = { FileTypeEnum.TORRENT };

        FileTypeEnum[] audios = { FileTypeEnum.WAV, FileTypeEnum.MP3 };

        FileTypeEnum[] others = {};

        // 图片
        for (FileTypeEnum fileType : pics) {
            if (fileType.equals(value)) {
                type = 1;
            }
        }
        // 文档
        for (FileTypeEnum fileType : docs) {
            if (fileType.equals(value)) {
                type = 2;
            }
        }
        // 视频
        for (FileTypeEnum fileType : videos) {
            if (fileType.equals(value)) {
                type = 3;
            }
        }
        // 种子
        for (FileTypeEnum fileType : tottents) {
            if (fileType.equals(value)) {
                type = 4;
            }
        }
        // 音乐
        for (FileTypeEnum fileType : audios) {
            if (fileType.equals(value)) {
                type = 5;
            }
        }
        return type;
    }
}
